import {useEffect, useState} from 'react';
import {IdentityModel} from '../db/models/identityModel';
import {
  DelegationChain,
  DelegationIdentity,
  Ed25519KeyIdentity,
} from '@dfinity/identity';

import {JsonnableDelegationChain} from '@dfinity/identity';
import {JsonnableEd25519KeyIdentity} from '@dfinity/identity/lib/cjs/identity/ed25519';

export interface IdentityStore {
  uid: string;
  delegationChain: DelegationChain;
  delegationIdentity: DelegationIdentity;
}

export type SiwpIdentityStorage = {
  uid: string;
  sessionIdentity: JsonnableEd25519KeyIdentity | string;
  delegationChain: JsonnableDelegationChain | string;
};

export function useIdentity() {
  const [getUserIdentityLoading, setGetUserIdentityLoading] =
    useState<boolean>(true);
  const [identityStore, setIdentityStore] = useState<IdentityStore | null>();

  const loadIdentity = async () => {
    setGetUserIdentityLoading(true);
    const identityModel = new IdentityModel();
    const identity = await identityModel.getSelected();
    if (identity == null) {
      setIdentityStore(null);
    } else {
      const s: SiwpIdentityStorage = JSON.parse(identity.data);
      if (!s.uid || !s.sessionIdentity || !s.delegationChain) {
        throw new Error('Stored state is invalid.');
      }
      const d = DelegationChain.fromJSON(s.delegationChain);
      const i = DelegationIdentity.fromDelegation(
        Ed25519KeyIdentity.fromJSON(
          typeof s.sessionIdentity == 'object'
            ? JSON.stringify(s.sessionIdentity)
            : s.sessionIdentity,
        ),
        d,
      );

      setIdentityStore({
        uid: identity.uid,
        delegationChain: d,
        delegationIdentity: i,
      });
    }

    setGetUserIdentityLoading(false);
  };

  const saveIdentity = async (
    uid: string,
    sessionIdentity: Ed25519KeyIdentity,
    delegationChain: DelegationChain,
  ) => {
    const identityModel = new IdentityModel();
    const data = JSON.stringify({
      uid: uid,
      sessionIdentity: sessionIdentity.toJSON(),
      delegationChain: delegationChain.toJSON(),
    });
    await identityModel.save({
      uid: uid,
      data: data,
      isSelected: 0,
    });

    await identityModel.setSelected(uid);
  };

  useEffect(() => {
    loadIdentity();
  }, []);

  return {
    getUserIdentityLoading,
    identityStore,
    setIdentityStore,
    saveIdentity,
  };
}
